import WhistleBridge from '..';
import { post } from '../request';

import type { DataType } from '../../types/base';
import type { WhistleBridgePlugin } from '../type';

export default class BridgePlugin implements WhistleBridgePlugin {
  public name: string = 'bridge';
  public root: WhistleBridge;
  public hasInitd: boolean = false;
  public originBridgeKey: string = '__WebViewJavascriptBridge';
  public excludePropKey = ['init'];
  public excludeHandlerName = ['sendWebStatInfo', 'init'];
  public receiveName = '_handleMessageFromObjC';

  private sendQueue: Record<string, any>[] = [];
  private sendTimer: any = null;

  static instance: BridgePlugin = null;

  private handler: ProxyHandler<any> = {
    get: (target, propKey, receiver) => {
      if (typeof target[propKey] === 'function') {
        return new Proxy(target[propKey], {
          apply: (applyTarget, thisArg, args) => {
            if (this.excludePropKey.includes(propKey as string) || this.excludeHandlerName.includes(args[1])) {
              // 过滤一些桥本身的方法，以及一些客户端协议名
            } else {
              const stack = new Error().stack;
              setTimeout(() => {
                // 如果有回调，则其__name会再该方法内部附加，则需要异步赋值
                if (typeof args[2] === 'function') {
                  args[3] = args[2].__name;
                }
                this.functionCalled(propKey as string, args, stack);
              }, 0);
            }

            return Reflect.apply(applyTarget, thisArg, args);
          },
        });
      }

      if (target.hasOwnProperty(propKey)) {
        return Reflect.get(target, propKey, receiver);
      }
    },
  };

  public onInit(params: any) {
    if (this.hasInitd) {
      return;
    }

    BridgePlugin.instance = this;
    this.root = params.root as WhistleBridge;

    if (window.WebViewJavascriptBridge) {
      this.initBridge();
    } else {
      document.addEventListener('WebViewJavascriptBridgeReady', this.initBridge.bind(this), false);
    }
  }

  // 桥接收数据输入的入口
  public get receiveMethod() {
    // @ts-ignore
    return window[this.originBridgeKey][this.receiveName];
  }

  private initBridge() {
    this.hasInitd = true;

    // @ts-ignore
    window[this.originBridgeKey] = window.WebViewJavascriptBridge;
    window.WebViewJavascriptBridge = new Proxy(window.WebViewJavascriptBridge, this.handler);

    // 发送页面基本信息，后端分配页面信息，以及后续的服务端推送的建立
    this.sendInfo().then(() => {
      this.root.setBridgePlugin(this);
      console.log('%c bridge plugin inited ', 'background: #222; color: #EE6A55');
    });
  }

  private functionCalled(propKey: string, args: any[], stack?: string) {
    this.sendData('CALL', {
      propKey,
      args,
      stack,
    });
  }

  private sendInfo() {
    const { config, status } = this.root;
    const payload = {
      type: 'INFO',
      data: status,
      name: config.name,
      time: Date.now(),
      receiveName: this.receiveName,
      originBridgeKey: this.originBridgeKey,
    };

    return post(config.baseUrl + '/info', {}, payload);
  }

  private sendData(type: DataType, data: Record<string, any>) {
    const { config } = this.root;
    const payload = {
      data,
      type,
      time: Date.now(),
    };

    this.sendQueue.push(payload);

    if (this.sendTimer) {
      return;
    }

    this.sendTimer = setTimeout(() => {
      this.sendTimer = null;
      post(config.baseUrl + '/batchSend', { name: config.name }, this.sendQueue.splice(0, this.sendQueue.length));
    }, config.sendDelay);
  }
}
